package com.smile.helper;

import com.alibaba.fastjson.JSON;
import com.smile.auth.JwtUserEntity;
import com.smile.util.AssertUtil;
import com.smile.util.RedisUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.Objects;

@Slf4j
@Component
public class TokenHelper {
    private static final String TOKEN_PREFIX = "token:";
    private static final String USER_PREFIX = "user:";

    @Value("${mall.mgt.tokenSecret:123456test}")
    private String tokenSecret;
    @Value("${mall.mgt.tokenExpireTimeInRecord:3600}")
    private int tokenExpireTimeInRecord;

    @Autowired
    private RedisUtil redisUtil;

    /**
     * 生成token
     *
     * @param userDetails 用户信息
     * @return token
     */
    public String generateToken(UserDetails userDetails) {
        String username = userDetails.getUsername();
        String token = Jwts.builder()
                .setSubject(username)
                .setExpiration(generateExpired())
                .signWith(SignatureAlgorithm.HS512, tokenSecret)
                .compact();
        redisUtil.set(getTokenKey(username), token, tokenExpireTimeInRecord);
        String userStr = JSON.toJSONString(userDetails);
        redisUtil.set(getUserKey(username), userStr, tokenExpireTimeInRecord);
        return token;
    }

    private String getTokenKey(String username) {
        return getKey(TOKEN_PREFIX, username);
    }

    private String getUserKey(String username) {
        return getKey(USER_PREFIX, username);
    }


    /**
     * 计算过期时间
     *
     * @return Date
     */
    private Date generateExpired() {
        return new Date(System.currentTimeMillis() + tokenExpireTimeInRecord * 1000);
    }

    private String getKey(String prefix, String userName) {
        return String.format("%s%s", prefix, userName);
    }

    /**
     * 从token中获取用户名
     * @param token token
     * @return 用户名
     */
    public String getUsernameFromToken(String token) {
        Claims claims = getClaimsFromToken(token);
        if (Objects.isNull(claims)) {
            return null;
        }
        return claims.getSubject();

    }

    /**
     * 从token中获取Claims
     *      * 该方法的底层是调用Jwts的parser方法，
     *      * 从token中解析出Claims实例，
     *      * 然后获取它的subject，它的值就是username。
     * @param token token
     * @return Claims
     */
    private Claims getClaimsFromToken(String token) {
        Claims claims;
        try {
            claims = Jwts.parser()
                    .setSigningKey(tokenSecret)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            log.warn("获得 Claims失败：", e);
            claims = null;
        }
        return claims;
    }

    public UserDetails getUserDetailsFromUsername(String username) {

        String userKey = getUserKey(username);
        String userDetailJson = redisUtil.get(userKey);
        if (Objects.isNull(userDetailJson)) {
            return null;
        }
        return JSON.parseObject(userDetailJson, JwtUserEntity.class);

    }

    public String getCurrentUsername() {
        final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        AssertUtil.notNull(authentication, "当前登录状态过期");
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        return userDetails.getUsername();
    }

    public void delToken(String token) {
        String username = getUsernameFromToken(token);
        redisUtil.del(getKey(TOKEN_PREFIX, username));
        redisUtil.del(getKey(USER_PREFIX, username));
    }
}
